package pl.dmcs.grails

import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
import pl.dmcs.grails.planner.PlannerEventService
import pl.dmcs.grails.planner.PlannerService
import grails.plugin.springsecurity.annotation.Secured
import pl.dmcs.grails.security.SecurityRole
import pl.dmcs.grails.security.UserSecurityRole

@Transactional(readOnly = true)
class EmployeeController {

    static allowedMethods = [save: "POST", update: "POST", delete: "DELETE"]

    PlannerService plannerService
    Employee employee

    @Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
    def index(Integer max) {
        def empCriteria = Employee.createCriteria()
        def notAssignedEmployees = empCriteria.list {
            isEmpty("employeeCategories")
            order("lastName")
        }
        [employeeCategoryInstanceList: EmployeeCategory.list(), notAssignedEmployeesList : notAssignedEmployees]
    }
    
    @Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
    def show(Employee employeeInstance) {
        //set to later use in the processPlannerEvents method
        employee = employeeInstance;
        def planner = this.preparePlannerCalendar(true);
        
        respond employeeInstance, model : [planner: planner.render()]
    }

    private boolean uploadAvatar(Employee employee, def request){
        def avatarFile = request.getFile('avatarInput')

        if(avatarFile.size != 0){
            if (!Employee.avatarTypes.contains(avatarFile.getContentType())) {
                employee.errors.reject( "Avatar must be one of: ${Employee.avatarTypes} type")
                return false
            }
            employee.avatar = avatarFile.bytes
            employee.avatarType = avatarFile.contentType
        }
        
        return true
    }
    
    @Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
    public getAvatar() {
        def employee = Employee.get(params.id)
        response.contentType = employee.avatarType
        response.contentLength = employee.avatar.size()
        
        //print the response
        OutputStream out = response.outputStream
        out.write(employee.avatar)
        out.close()
    }
    
    @Secured(["ROLE_DMCS_ADMIN"])
    def create() {
        respond new Employee(params)
    }

    @Secured(["ROLE_DMCS_ADMIN"])
    @Transactional
    def save(Employee employeeInstance) {
        if (employeeInstance == null) {
            notFound()
            return
        }
        
        if (!uploadAvatar(employeeInstance, request)) {
            return false;
        }
        
		setupPasswordChange(employeeInstance, params);
        
        if (employeeInstance.hasErrors()) {
            respond employeeInstance.errors, view:'create'
            return
        }

        employeeInstance.save flush:true, failOnError: true
		
		setupEmployeeRoles(employeeInstance, params);

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [
                        message(code: 'employee.label', default: 'Employee'),
                        employeeInstance.id
                    ])
                redirect employeeInstance
            }
	'*' { respond employeeInstance, [status: CREATED] }
        }
    }

    @Secured(["ROLE_DMCS_USER", "ROLE_DMCS_ADMIN"])
    def edit(Employee employeeInstance) {
        //set to later use in the processPlannerEvents method
        employee = employeeInstance;
        
        def planner = this.preparePlannerCalendar();

        respond employeeInstance, model : [planner: planner.render()]
    }
    
    @Secured(["IS_AUTHENTICATED_ANONYMOUSLY"])
    @Transactional
    def processPlannerEvents() {
        PlannerEventService evs = new PlannerEventService(request, employee);
        render evs.run();
    }
    
    private preparePlannerCalendar(boolean readOnly = false) {
        String pathToPlannerScripts = g.resource(dir: 'codebase') + "/"
        def planner = plannerService.getPlanner(readOnly, pathToPlannerScripts, g.createLink(uri: '/') + "processPlannerEvents");
    }

    @Secured(["ROLE_DMCS_USER", "ROLE_DMCS_ADMIN"])
    @Transactional
    def update(Employee employeeInstance) {
        if (employeeInstance == null) {
            notFound()
            return
        }
        
        if (!uploadAvatar(employeeInstance, request)) {
            return false;
        }
        
        setupPasswordChange(employeeInstance, params);
		setupEmployeeRoles(employeeInstance, params);

        if (employeeInstance.hasErrors()) {
			def planner = this.preparePlannerCalendar();
            respond employeeInstance.errors, view:'edit', model : [planner: planner.render()]
            return
        }
        
        employeeInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [
                        message(code: 'Employee.label', default: 'Employee'),
                        employeeInstance.id
                    ])
                redirect employeeInstance
            }
	'*'{ respond employeeInstance, [status: OK] }
        }
    }
    
    private void setupPasswordChange(Employee employeeInstance, def params){
        String pass = params.pass;
        String passwordConfirm = params.passwordConfirm;
        if (pass) {
            if(pass == passwordConfirm){
                employeeInstance.password = pass;
				employeeInstance.validate();
            } else{
				employeeInstance.validate();
                employeeInstance.errors.reject("Password and Password confirmation must be equals")
            }
        }
    }
	
	private void setupEmployeeRoles(Employee employeeInstance, def params) {
		def employeeRoles = params.employeeRoles;
		
		if (employeeInstance?.id != null) {
			UserSecurityRole.removeAll(employeeInstance, true)
		}

		if (employeeRoles) {
			employeeRoles.each{
				UserSecurityRole.create(employeeInstance, SecurityRole.findById(it), true)
			}
		}
	}

    @Secured(["ROLE_DMCS_ADMIN"])
    @Transactional
    def delete(Employee employeeInstance) {

        if (employeeInstance == null) {
            notFound()
            return
        }
	
		UserSecurityRole.removeAll(employeeInstance, true)
			
        employeeInstance.delete flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [
                        message(code: 'Employee.label', default: 'Employee'),
                        employeeInstance.id
                    ])
                redirect action:"index", method:"GET"
            }
	'*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [
                        message(code: 'employee.label', default: 'Employee'),
                        params.id
                    ])
                redirect action: "index", method: "GET"
            }
	'*'{ render status: NOT_FOUND }
        }
    }
}
